#-*- coding: utf8 -*-
#TODO: o segundo ponto é sempre um ponto de sela!

from tutor.script import *
from tutor.plugin.maple import *

# meta information
meta(author       = 'Fábio Mendes',
     creationdate = datetime(2010, 10, 23),
     status       = 'testing',
     difficulty   = 'easy',
     time         = 10,
     itemtype     = 'test')

# sorteia parâmetros
a = oneof(-1, 1) * oneof(1,2,3,4,6,8,9,10,12,15) / M(6)
g = oneof(-1, 1, 1) * oneof(1,2,3,4,8,9,10,12,15) / M(6)

# 1/4 de chance do teste falhar no segundo ponto (gamma = -1/2)
g = oneof(-M(1)/2, g, g, g)
 
# define a função
u,v = sample([x,y], 2)
func = u**3/3 -(a+v) * u**2/2 + a*u*v + a*g*v**2/2
print('function: %s' % func)

# define respostas
options = {  1: 'é um ponto de máximo.', 
            -1: 'é um ponto de mínimo.', 
             0: 'é um ponto de sela.', 
             None: 'o teste falha.' }

# calcula Hessiana
fxx = diff(func, x, x)
fyy = diff(func, y, y)
fxy = diff(func, x, y)
fx = diff(func, x)
fy = diff(func, y)

# traco e determinante
det = M.unapply(fxx * fyy - fxy**2, x, y)
tr = M.unapply(fxx + fyy, x, y)
grad = M.unapply([fx, fy], x, y)

# começa questão
question('Para responder as perguntas abaixo, encontre todos os pontos críticos da função\n\n'
         '          $$f(x,y) = ', func, '.$$\n\n')

#
# Um dos pontos críticos fica exatamente na origem
#
question(u'I) Utilizando o teste da segunda derivada sobre o \n'
          'ponto crítico mais próximo à origem, podemos afirmar que:')
multiplechoice()

# verifica se é máximo mínimo ou sela pelo teste da Hessiana
assert grad(0, 0) == [0, 0], grad(0, 0)
det0 = det(0, 0)
tr0 = tr(0, 0)
bad = options.copy()

if det0 < 0:
    good = bad.pop(0) # sela
elif det0 > 0:
    if tr0 > 0:
        good = bad.pop(-1) # minimo
    else:
        good = bad.pop(1) # maximo
else:
    good = bad.pop(None) # falha

# itera sobre as respostas ruins
bad = bad.itervalues()
print('origem, det=%s, tr=%s' % (det0, tr0))        

choice(0.5, good)
choice(0, bad.next())
choice(0, bad.next())
choice(0, bad.next())

#
# Ponto mais afastado
#
question(u'II) Com relação ao ponto mais distante da reta $x=y$ é possível afirmar que:')
multiplechoice()

# define o ponto
if x == u:
    pt1 = (a, -a/(2*g))
else:
    pt1 = (-a/(2*g), a)
assert grad(*pt1) == [0, 0], [ pt1, grad(*pt1) ]
assert pt1 != (0,0)

# calcula determinante e traço
det0 = det(*pt1)
tr0 = tr(*pt1)
bad = options.copy()

if det0 < 0:
    good = bad.pop(0) # sela
elif det0 > 0:
    if tr0 > 0:
        good = bad.pop(-1) # minimo
    else:
        good = bad.pop(1) # maximo
else:
    good = bad.pop(None) # falha

# itera sobre as respostas ruins
bad = bad.itervalues()
print('ponto %s, det=%s, tr=%s' % (pt1, det0, tr0))        

choice(0.5, good)
choice(0, bad.next())
choice(0, bad.next())
choice(0, bad.next())

end()